<?php
// +----------------------------------------------------------------------
// | SwiftPHP [ JUST DO ONE THING WELL ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015-2017  http://swiftphp.zhongwenyu.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhongwenyu <zhongwenyu1987@163.com> <http://www.zhongwenyu.com>
// +----------------------------------------------------------------------
// | Times: 2017/2/16 21:17
// +----------------------------------------------------------------------
namespace swift;

class Route{
    // 路由规则
    private static $rules = [
        'get'     => [],  //get请求
        'post'    => [],  //post请求
        'put'     => [],  //put请求
        'delete'  => [],  //DELETE 请求
        'patch'   => [],  //Patch 请求
        'head'    => [],  //HEAD 请求
        'options' => [],  //路由参数，主要用于验证当前的路由规则是否有效，例如 get，post
        '*'       => [],
        'alias'   => [],  //路由别名
        'domain'  => [],  //域名部署
        'pattern' => [],  //变量规则，约束变量的类型用以匹配，例如 'id'=>'\d+'
        'name'    => [],  //参数规则
    ];

    private static $group = [];

    // 当前域名
    private static $domain;
    // 当前子域名
    private static $subDomain = '';
    // 域名绑定
    private static $bind = [];
    // 当前绑定域名参数
    private static $bindDomain = '';
    private static $option = [];

    /**
     * 获取或者批量设置路由定义
     * @access public
     * @param mixed $rules 请求类型或者路由定义数组
     * @return array
     */
    public static function rules($rules = ''){
        if(is_array($rules)){
            self::$rules = $rules;
        }elseif($rules){
            return true === $rules ? self::$rules : self::$rules[strtolower($rules)];
        }else{
            $rules = self::$rules;
            unset($rules['pattern'], $rules['alias'], $rules['domain'], $rules['name']);
            return $rules;
        }
    }

    /**
     * 检测URL路由
     * @access public
     * @param Request   $request Request请求对象
     * @param string    $url URL地址
     * @param string    $depr URL分隔符
     * @param bool      $checkDomain 是否检测域名规则
     * @return false|array
     */
    public static function check($request, $url, $depr = '/', $checkDomain = false){
        // 分隔符替换，确保使用同一分隔符
        $url = str_replace($depr , '|' , $url);

        $method = strtolower($request->method());
        // 获取当前请求类型的路由规则
        $rules = self::$rules[$method];

        //检测域名部署
        if ($checkDomain) {
            self::checkDomain($request, self::$rules, $method);
        }

        //检测路由别名
        if(isset(self::$rules['alias'][strpos($url , '|') ? strstr($url , '|' ,true) : $url])){
            $result = self::checkRouteAlias($request, $url, $depr);
            if(false !== $result){
                return $result;
            }
        }
        $url = trim($url , '|');
        $item = str_replace('|', '/', $url);
        // 静态路由规则检测
        if(isset($rules[$item])){
            $rule = $rules[$item];
            if(true === $rule){
                $rule = self::getRouteExpress($item);
            }
            if(!empty($rule['route']) && self::checkOption($rule['option'],$request)){
                self::setOption($rule['option']);
                return self::parseRule($item,$rule['route'],$url, $rule['option']);
            }
        }
        // 路由规则检测
        $result = self::checkRoute($request, $rules, $url, $depr);
        if($result != false){
            return $result;
        }else{
            // 无匹配路由
            return self::parseUrl($url, $depr);
        }
    }

    /**
     * 解析模块的URL地址 [模块/控制器/操作?]参数1=值1&参数2=值2...
     * @access public
     * @param string    $url URL地址
     * @param string    $depr URL分隔符
     * @param bool      $autoSearch 是否自动深度搜索控制器
     * @return array
     */
    public static function parseUrl($url, $depr = '/', $autoSearch = false){
        // 检测域名绑定
        if(!empty(self::$bind)){
            $url = !empty(trim($url , $depr)) ? self::$bind['module'] . $depr . $url : self::$bind['module'];
            if(substr_count($url , $depr) > 2){
                throw new \Exception($url.' 非法请求！');
            }
        }

        // 使用统一的分隔符
        $url              = str_replace($depr, '|', $url);
        list($path, $var) = self::parseUrlPath($url);
        $route            = [null, null, null];
        if (isset($path)) {
            // 解析模块
            $module = array_shift($path);
            $module = strtolower($module ?: Config::get('default_module'));
            // 解析控制器
            $controller = strtolower(empty($path) ? Config::get('default_controller') : array_shift($path));
            // 解析操作
            $action = strtolower(empty($path) ? Config::get('default_action') : array_shift($path));

            // 检测路由地址唯一性
            $name = $module . '/' . $controller . '/' . $action;
            self::routeUnique($name , $depr);

            // 设置绑定参数
            self::parseUrlParams(empty($path) ? '' : implode('|' , $path));

            //自动搜索控制器
            $dir = APP_PATH . $module . DS . Config::get('url_controller_layer') . DS . $controller . EXT;
            if(is_file($dir)){
                $route = [$module, $controller, $action];
                return ['type' => 'module', 'module' => $route];
            }else{
                throw new \Exception('/'.$module.'/'.$controller.' 控制器不存在！');
            }
        }
    }

    /**
     * 检测路由地址唯一性
     */
    protected static function routeUnique($url , $depr){
        // 检测地址是否被注册过路由
        $hasRoute = false;
        if(isset(self::$rules['name'][$url])){
            $hasRoute = true;
        }
        // 检测别名路由唯一性
        if(!empty(self::$rules['alias'])){
            foreach(self::$rules['alias'] as $val){
                if(0 === strpos($url , $val)) $hasRoute = true;
            }
        }
        if($hasRoute){
            throw new \Exception($url.' 非法请求！');
        }
    }

    /**
     * 检测路由规则
     * @access private
     * @param Request   $request
     * @param array     $rules 路由规则
     * @param string    $url URL地址
     * @param string    $depr URL分割符
     * @param string    $group 路由分组名
     * @param array     $options 路由参数（分组）
     * @return mixed
     */
    private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = []){
        foreach($rules as $key => $item){
            if(true === $item){
                $item = self::getRouteExpress($key);
            }
            if(!isset($item['rule'])){
                continue;
            }
            $rule    = $item['rule'];
            $route   = $item['route'];
            $option  = $item['option'];
            $pattern = $item['pattern'];

            // 检查参数有效性
            if (!self::checkOption($option, $request)) {
                continue;
            }
            if(is_array($rule)){
                // 分组路由
                if(is_string($key) && $key && 0 !== strpos(str_replace('|','/',$url),$key)){
                    // 路由不匹配，进入下一循环
                    continue;
                }
                self::setOption($option);
                $result = self::checkRoute($request, $rule, $url, $depr, $key, $option);
                if (false !== $result) {
                    return $result;
                }
            }else{
                if ($group) {
                    $rule = $group . ($rule ? '/' . ltrim($rule, '/') : '');
                }
                // 参数检查
                if(!self::checkOption($option,$request)){
                    continue;
                }
                $result = self::checkRule($rule, $route, $url, $pattern, $option, $depr);
                if (false !== $result) {
                    return $result;
                }
            }
        }
        return false;
    }

    /**
     * 检测路由规则
     * @access private
     * @param string    $rule 路由规则
     * @param string    $route 路由地址
     * @param string    $url URL地址
     * @param array     $pattern 变量规则
     * @param array     $option 路由参数
     * @param string    $depr URL分隔符（全局）
     * @return array|false
     */
    private static function checkRule($rule, $route, $url, $pattern, $option, $depr){
        $pattern = array_merge(self::$rules['pattern'], $pattern);
        if (false !== $match = self::match($url, $rule, $pattern)) {
            // 匹配到路由规则
            return self::parseRule($rule, $route, $url, $option, $match);
        }else{
            return false;
        }
    }

    /**
     * 检测URL和规则路由是否匹配
     * @access private
     * @param string    $url URL地址
     * @param string    $rule 路由规则
     * @param array     $pattern 变量规则
     * @return array|false
     */
    private static function match($url, $rule, $pattern){
        $rule = explode('/', $rule);
        $url = explode('|', $url);

        $var = [];
        foreach($rule as $key => $val){
            if(0 === strpos($val,'[')){
                // 可选参数
                $val      = substr($val, 1, -1);
                $optional = true;
            }else{
                $optional = false;
            }
            if(0 === strpos($val,':')){
                // URL变量
                $name = substr($val, 1);
                if(!$optional && !isset($url[$key])){
                    //这里表示如果不是可选参数，则url地址中必须要有相应的参数
                    return false;
                }
                if(isset($url[$key]) && isset($pattern[$name])){
                    if (!preg_match('/^' . $pattern[$name] . '$/', $url[$key])) {    //使用正则检查
                        return false;
                    }
                }
                $var[$name] = isset($url[$key]) ? $url[$key] : '';
            }elseif (!isset($url[$key]) || 0 !== strcasecmp($val, $url[$key])) {
                return false;
            }
        }
        // 成功匹配后返回URL中的动态变量数组
        return $var;
    }

    /**
     * 解析规则路由
     * @access private
     * @param string    $rule 路由规则
     * @param string    $route 路由地址
     * @param string    $pathinfo URL地址
     * @param array     $option 路由参数
     * @param array     $matches 匹配的变量
     * @return array
     */
    private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = []){
        $request = Request::instance();
        $paths = explode('|',$pathinfo);
        if($rule){
            $rule = explode('/',$rule);
            // 获取URL地址中的参数
            foreach($rule as $item){
                if(0 === strpos($item , '[')){
                    $item = substr($item , 1 , -1);
                }
                if(0 === strpos($item , ':')){
                    $var = substr($item , 1);
                    $matches[$var] = array_shift($paths);
                }else{
                    // 过滤URL中的静态变量
                    array_shift($paths);
                }
            }
        }
        // 解析额外参数
        self::parseUrlParams(empty($paths) ? '' : implode('|', $paths), $matches);
        // 记录匹配的路由信息
        $request->routeInfo(['rule' => $rule, 'route' => $route, 'option' => $option, 'var' => $matches]);
        // 路由到模块/控制器/操作
        $result = self::parseModule($route);
        return $result;
    }

    /**
     * 解析URL地址中的参数Request对象
     * @access private
     * @param string    $rule 路由规则
     * @param array     $var 变量
     * @return void
     */
    private static function parseUrlParams($url, &$var = []){
        if($url){
            preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
                $var[$match[1]] = strip_tags($match[2]);
            }, $url);
        }
        // 设置当前请求的参数
        Request::instance()->route($var);
    }

    /**
     * 解析URL地址为 模块/控制器/操作
     * @access private
     * @param string    $url URL地址
     * @return array
     */
    private static function parseModule($url){
        list($path , $var) = self::parseUrlPath($url);
        $action = !empty($path) ? array_pop($path) : Config::get('default_action');
        $controller = !empty($path) ? array_pop($path) : Config::get('default_controller');
        $module = !empty($path) ? array_pop($path) : Config::get('default_module');
        // 设置当前请求的路由变量
        Request::instance()->route($var);
        // 路由到模块/控制器/操作
        return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false];
    }

    /**
     * 解析URL的pathinfo参数和变量
     * @access private
     * @param string    $url URL地址
     * @return array
     */
    private static function parseUrlPath($url){
        // 分隔符替换 确保路由定义使用统一的分隔符
        $url = str_replace('|','/',$url);
        $url = trim($url, '/');
        $var = [];
        if (false !== strpos($url, '?')) {
            // [模块/控制器/操作?]参数1=值1&参数2=值2...
            $info = parse_url($url);
            $path = explode('/', $info['path']);
            parse_str($info['query'], $var);
        } elseif (strpos($url, '/')) {
            // [模块/控制器/操作]
            $path = explode('/', $url);
        } elseif (false !== strpos($url, '=')) {
            // 参数1=值1&参数2=值2...
            parse_str($url, $var);
        } else {
            $path = [$url];
        }
        return [$path, $var];
    }

    /**
     * 设置当前执行的参数信息
     * @access public
     * @param array    $options 参数信息
     * @return mixed
     */
    protected static function setOption($options = [])
    {
        self::$option[] = $options;
    }

    private static function getRouteExpress($key)
    {
        $return = self::$rules['domain'][self::$bindDomain][$key];
        if(!empty($return)){
            return $return;
        }else{
            $return = self::$rules['*'][$key];
            if(self::checkDomainBind($return)){
                return $return;
            }else{
                return false;
            }
        }
    }

    // 检测域名绑定
    protected static function checkDomainBind($rule){
        if(empty(self::$bind)){
            return true;
        }else{
            if(is_array($rule['rule'])){
                foreach($rule['rule'] as $key => $val){
                    if(0 !== strpos($val['route'] , self::$bind['module'])){
                        unset($rule[$key]);
                    }
                }
                return empty($rule) ? false : $rule;
            }else{
                return (0 !== strpos($rule['route'] , self::$bind['module'])) ? false : $rule;
            }
        }
    }

    /**
     * 检测子域名部署
     * @access public
     * @param Request   $request Request请求对象
     * @param array     $currentRules 当前路由规则
     * @param string    $method 请求类型
     * @return void
     */
    public static function checkDomain($request, &$currentRules, $method = 'get'){
        // 域名规则
        $rules = self::$rules['domain'];
        // 开启子域名部署 支持二级和三级域名
        if(!empty($rules)){
            $host = $request->host();
            // 完整域名部署
            if(isset($rules[$host])){
                $item = $rules[$host];
            } else {
                $domain = explode('.' , $host , -2);
                // 子域名配置
                if(!empty($domain)){
                    // 当前子域名
                    $subDomain = implode('.' , $domain);
                    self::$subDomain = $subDomain;
                    $domain2 = array_pop($domain);
                    if($domain){
                        // 存在三级域名
                        $domain3 = array_pop($domain);
                    }
                    if($subDomain && isset($rules[$subDomain])){
                        // 子域名配置
                        self::$bindDomain = $subDomain;
                        $item = $rules[self::$bindDomain];
                    } elseif (isset($rules['*.'.$domain2]) && !empty($domain3)){
                        // 泛三级域名
                        self::$bindDomain = '*.'.$domain2;
                        $item = $rules[self::$bindDomain];
                        $panDomain = $domain3;
                    } elseif(isset($rules['*.']) && !empty($domain2)){
                        // 泛二级域名
                        if('www' != $domain2){
                            self::$bindDomain = '*.';
                            $item = $rules[self::$bindDomain];
                            $panDomain = $domain2;
                        }
                    }
                }
            }
            if(!empty($item)){
                if (isset($panDomain)) {
                    // 保存当前泛域名
                    $request->route(['__domain__' => $panDomain]);
                }
                if(isset($item['[bind]'])){
                    // 解析子域名部署规则
                    list($rule , $option , $pattern) = $item['[bind]'];
                    // 绑定到模块/控制器 例如 index/user
                    self::$bind = ['type' => 'module', 'module' => $rule];
                }
            }
        }
    }

    /**
     * 检测路由别名
     * @access private
     * @param Request   $request
     * @param string    $url URL地址
     * @param string    $depr URL分隔符
     * @return mixed
     */
    private static function checkRouteAlias($request, $url, $depr){
        $array = explode('|' , $url);
        $alias = array_shift($array);
        $item = self::$rules['alias'][$alias];
        if(is_array($item)){
            list($rule, $option) = $item;
            if(!empty($array)){
                $action              = $array[0];
                if (isset($option['allow']) && !in_array($action, explode(',', $option['allow']))) {
                    // 允许操作
                    return false;
                } elseif (isset($option['except']) && in_array($action, explode(',', $option['except']))) {
                    // 排除操作
                    return false;
                }
                if (isset($option['method'][$action])) {
                    $option['method'] = $option['method'][$action];
                }
            }
        } else {
            $rule = $item;
        }
        $bind = implode($depr , $array);
        if (isset($option) && !self::checkOption($option, $request)) {
            // 参数有效性检查
            return false;
        } else {
            // 路由到模块/控制器
            return self::bindToModule($bind, $rule, $depr);
        }
    }

    /**
     * 绑定到模块/控制器
     * @access public
     * @param string    $url URL地址
     * @param string    $controller 控制器类名（带命名空间）
     * @param string    $depr URL分隔符
     * @return array
     */
    public static function bindToModule($url, $controller, $depr = '/'){
        $url = str_replace($depr , '|' , $url);
        $array = explode('|', $url, 2);
        $module = explode('/',$controller);
        if(substr_count($controller , '/') < 2){
            $action = !empty($array[0]) ? $array[0] : Config::get('default_action');
            $module[] = $action;
        }
        return ['type' => 'module', 'module' => $module];
    }

    /**
     * 路由参数有效性检查
     * @access private
     * @param array     $option 路由参数
     * @param Request   $request Request对象
     * @return bool
     */
    private static function checkOption($option, $request)
    {
        if ((isset($option['method']) && is_string($option['method']) && false === stripos($option['method'], $request->method()))
            || (isset($option['ajax']) && $option['ajax'] && !$request->isAjax()) // Ajax检测
            || (isset($option['ajax']) && !$option['ajax'] && $request->isAjax()) // 非Ajax检测
            || (isset($option['pjax']) && $option['pjax'] && !$request->isPjax()) // Pjax检测
            || (isset($option['pjax']) && !$option['pjax'] && $request->isPjax()) // 非Pjax检测
            || (isset($option['ext']) && false === stripos('|' . $option['ext'] . '|', '|' . $request->ext() . '|')) // 伪静态后缀检测
            || (isset($option['deny_ext']) && false !== stripos('|' . $option['deny_ext'] . '|', '|' . $request->ext() . '|'))
            || (isset($option['domain']) && !in_array($option['domain'], [$_SERVER['HTTP_HOST'], self::$subDomain])) // 域名检测
            || (isset($option['https']) && $option['https'] && !$request->isSsl()) // https检测
            || (isset($option['https']) && !$option['https'] && $request->isSsl()) // https检测
            || (!empty($option['callback']) && is_callable($option['callback']) && false === call_user_func($option['callback'])) // 自定义检测
        ) {
            return false;
        }
        return true;
    }

    /**
     * 导入配置文件的路由规则
     * @access public
     * @param array     $rule 路由规则
     * @param string    $type 请求类型
     * @return void
     */
    public static function import(array $rule, $type = '*'){
        // 检查域名部署
        if(isset($rule['__domain__'])){
            self::domain($rule['__domain__']);
            unset($rule['__domain__']);
        }

        // 检查变量规则
        if(isset($rule['__pattern__'])){
            self::pattern($rule['__pattern__']);
            unset($rule['__pattern__']);
        }

        // 检查路由别名
        if (isset($rule['__alias__'])) {
            self::alias($rule['__alias__']);
            unset($rule['__alias__']);
        }

        self::registerRules($rule , strtolower($type));
    }

    // 批量注册路由
    protected static function registerRules($rules, $type = '*'){
        foreach($rules as $key => $val){
            if(empty($val)){
                continue;
            }elseif(is_string($key) && 0 === strpos($key , '{')){
                // 域名分组路由注册
                $key = substr($key,1,-1);
                foreach($val as $k => $v){
                    if(isset(self::$rules['domain'][$k])){
                        self::domainGroup($key , $k , $v);
                    }
                }
            }elseif(is_string($key) && 0 === strpos($key , '[')){
                // 分组路由注册
                $key = substr($key,1,-1);
                self::group($key , $val);
            } elseif (is_array($val)) {
                // 单个路由注册
                self::setRule($key, $val[0], $type, $val[1], isset($val[2]) ? $val[2] : []);
            } else{
                // 单个路由注册
                self::setRule($key , $val , $type);
            }
        }

        // 路由缓存
        self::cache();
    }

    /**
     * 设置路由规则
     * @access public
     * @param string    $rule 路由规则
     * @param string    $route 路由地址
     * @param string    $type 请求类型
     * @param array     $option 路由参数
     * @param array     $pattern 变量规则
     * @param string    $group 所属分组
     * @return void
     */
    protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = ''){
        if (is_array($rule)) {
            $name = $rule[0];
            $rule = $rule[1];
        } elseif (is_string($route)) {
            $name = $route;
        }
        if (!isset($option['complete_match'])) {
            if (Config::get('route_complete_match')) {
                $option['complete_match'] = true;
            } elseif ('$' == substr($rule, -1, 1)) {
                // 是否完整匹配
                $option['complete_match'] = true;
            }
        } elseif (empty($option['complete_match']) && '$' == substr($rule, -1, 1)) {
            // 是否完整匹配
            $option['complete_match'] = true;
        }
        if ('$' == substr($rule, -1, 1)) {
            $rule = substr($rule, 0, -1);
        }
        $vars = self::parseVar($rule);
        if(isset($name)){
            $key    = $group ? $group . ($rule ? '/' . $rule : '') : $rule;
            self::name($name, [$key, $vars, self::$domain]);
        }
        self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern];
        if ('*' == $type) {
            // 注册路由快捷方式
            foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
                if (self::$domain) {
                    self::$rules['domain'][self::$domain][$method][$rule] = true;
                } else {
                    self::$rules[$method][$rule] = true;
                }
            }
        }
    }

    /**
     * 注册域名路由分组
     * @access public
     * @param string|array      $name 分组名称
     * @param array             $domain 路由参数
     * @param array|\Closure    $routes 路由地址
     * @return void
     */
    public static function domainGroup($name, $domain , $routes){
        $item  = [];
        foreach($routes as $key => $val){
            if(is_array($val)){
                $route = $val[0];
                $option1 = isset($val[1]) ? $val[1] : [];
                $pattern1 = isset($val[2]) ? $val[1] : [];
            }else{
                $route = $val;
            }
            $options = isset($option1) ? $option1 : [];
            $patterns = isset($pattern1) ? $pattern1 : [];
            // 是否完整匹配
            if('$' == substr($key , -1 ,1)){
                $options['complete_match'] = true;
                $key                       = substr($key, 0, -1);
            }
            $key = trim($key , '/');
            $route = self::$rules['domain'][$domain]['[bind]'][0] . '/' . $route;
            $vars = self::parseVar($key);   // 提取路由地址中的变量
            $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns];
            self::name($route,[$name . ($key ? '/' . $key : ''), $vars, self::$domain]);
        }
        self::$rules['domain'][$domain][$name] = ['rule' => $item , 'route' => '', 'var' => [], 'option' => [], 'pattern' => []];
        foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
            if (!isset(self::$rules[$method][$name])) {
                self::$rules[$method][$name] = true;
            } elseif (is_array(self::$rules[$method][$name])) {
                self::$rules[$method][$name] = array_merge(self::$rules['*'][$name], self::$rules[$method][$name]);
            }
        }
    }

    /**
     * 注册路由分组
     * @access public
     * @param string|array      $name 分组名称或者参数
     * @param array|\Closure    $routes 路由地址
     * @param array             $option 路由参数
     * @param array             $pattern 变量规则
     * @return void
     */
    public static function group($name, $routes, $option = [], $pattern = []){
        $item  = [];
        foreach($routes as $key => $val){
            if(is_array($val)){
                $route = $val[0];
                $option1 = array_merge($option , isset($val[1]) ? $val[1] : []);
                $pattern1 = array_merge($pattern , isset($val[2]) ? $val[2] : []);
            }else{
                $route = $val;
            }
            $options = isset($option1) ? $option1 : $option;
            $patterns = isset($pattern1) ? $pattern1 : $pattern;
            // 是否完整匹配
            if('$' == substr($key , -1 ,1)){
                $options['complete_match'] = true;
                $key                       = substr($key, 0, -1);
            }
            $key = trim($key , '/');
            $vars = self::parseVar($key);   // 提取路由地址中的变量
            $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns];
            self::name($route,[$name . ($key ? '/' . $key : ''), $vars, self::$domain]);
        }
        self::$rules['*'][$name] = ['rule' => $item , 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern];
        foreach (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'] as $method) {
            if (!isset(self::$rules[$method][$name])) {
                self::$rules[$method][$name] = true;
            } elseif (is_array(self::$rules[$method][$name])) {
                self::$rules[$method][$name] = array_merge(self::$rules['*'][$name], self::$rules[$method][$name]);
            }
        }
    }

    /**
     * 设置或者获取路由标识
     * @access public
     * @param string|array     $name 路由命名标识 数组表示批量设置
     * @param array            $value 路由地址及变量信息
     * @return array
     */
    public static function name($name = '', $value = null){
        if(is_array($name)){
            return self::$rules['name'] = $name;
        } elseif ('' == $name){
            return self::$rules['name'];
        } elseif (!is_null($value)){
            self::$rules['name'][strtolower($name)][] = $value;
        } else{
            $name = strtolower($name);
            return isset(self::$rules['name'][$name]) ? self::$rules['name'][$name] : null;
        }
    }

    // 分析路由规则中的变量
    private static function parseVar($rule){
        $vars = [];
        foreach(explode('/' , $rule) as $val){
            $optional = false;
            //可选变量
            if(0 === strpos($val , '[:')){
                $optional = true;
                $val = substr($val , 1 , -1);
            }
            if(0 === strpos($val , ':')){
                $name = substr($val , 1);
                $vars[$name] = $optional ? 2 : 1;
            }
        }
        return $vars;
    }

    /**
     * 获取当前的分组信息
     * @access public
     * @param string    $type 分组信息名称 name option pattern
     * @return mixed
     */
    public static function getGroup($type)
    {
        if (isset(self::$group[$type])) {
            return self::$group[$type];
        } else {
            return 'name' == $type ? null : [];
        }
    }

    // 生成路由缓存
    private static function cache(){
        if (!is_file(RUNTIME_PATH . 'route.php')) {
            is_dir(RUNTIME_PATH) || mkdir(RUNTIME_PATH , 0777 , true);
            $config = <<<str
<?php
//路由缓存文件
return
str;
            file_put_contents(RUNTIME_PATH . 'route.php' , $config .' '. var_export(self::$rules , true) . ';');
        }
    }

    /**
     * 注册别名路由
     * @access public
     * @param string|array  $rule 路由别名
     * @param string        $route 路由地址
     * @param array         $option 路由参数
     * @return void
     */
    public static function alias($rule = null, $route = '', $option = [])
    {
        if (is_array($rule)) {
            self::$rules['alias'] = array_merge(self::$rules['alias'], $rule);
        } else {
            self::$rules['alias'][$rule] = $option ? [$route, $option] : $route;
        }
    }

    /**
     * 注册子域名部署规则
     * @access public
     * @param string|array  $domain 子域名
     * @param mixed         $rule 路由规则
     * @param array         $option 路由参数
     * @param array         $pattern 变量规则
     * @return void
     */
    public static function domain($domain, $rule = '', $option = [], $pattern = []){
        if(is_array($domain)){
            foreach($domain as $key => $item){
                self::domain($key , $item , $option , $pattern);
            }
        }else{
            self::$rules['domain'][$domain]['[bind]'] = [$rule , $option , $pattern];
        }
    }

    /**
     * 注册变量规则
     * @access public
     * @param string|array  $name 变量名
     * @param string        $rule 变量规则
     * @return void
     */
    public static function pattern($name = null, $rule = ''){
        if(is_array($name)){
            self::$rules['pattern'] = array_merge(self::$rules['pattern'] , $name);
        }else{
            self::$rules['pattern'][$name] = $rule;
        }
    }
}